package tictactoe;

//~--- JDK imports ------------------------------------------------------------

import java.awt.Point;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @version 1
 * @author buya
 */
public class Desk implements Cloneable {

    /**
     *
     */
    public static final int CIRCLE = 0;

    /**
     *
     */
    public static final int CROSS = 1;

    /**
     *
     */
    public static final int NO_WINNER = -1;
    private Set<Point>      cross     = new HashSet<Point>();
    private Set<Point>      circle    = new HashSet<Point>();
    private int             width, height;

    /**
     *
     * @param width
     * @param height
     */
    public Desk(int width, int height) {
        this.width  = width;
        this.height = height;
    }

    /**
     *
     * @return
     */
    public int getWidth() {
        return width;
    }

    /**
     *
     * @return
     */
    public int getHeight() {
        return height;
    }

    /**
     *
     * @return
     */
    public Set<Point> getCrosses() {
        return Collections.unmodifiableSet(cross);
    }

    /**
     *
     * @return
     */
    public Set<Point> getCircles() {
        return Collections.unmodifiableSet(circle);
    }

    /**
     *
     * @return
     */
    public int getWinner() {
        if (checkCross()) {
            return CROSS;
        }

        if (checkCircle()) {
            return CIRCLE;
        }

        return NO_WINNER;
    }

    /**
     *
     * @param where
     * @return
     */
    public boolean canPlace(Point where) {
        if ((where.x < 0) || (where.x >= width) || (where.y < 0) || (where.y >= height)) {
            return false;
        }

        return !cross.contains(where) &&!circle.contains(where);
    }

    /**
     *
     * @param x
     * @param y
     * @return
     */
    public boolean canPlace(int x, int y) {
        return canPlace(new Point(x, y));
    }

    /**
     *
     * @param player
     * @param where
     * @return
     */
    public boolean add(int player, Point where) {
        if ((where.x < 0) || (where.x >= width) || (where.y < 0) || (where.y >= height)) {
            throw new IllegalArgumentException("where");
        }

        switch (player) {
        case CROSS :
            return cross.add(where);

        case CIRCLE :
            return circle.add(where);

        default :
            throw new IllegalArgumentException("player");
        }
    }

    /**
     *
     * @param player
     * @param x
     * @param y
     * @return
     */
    public boolean add(int player, int x, int y) {
        return add(player, new Point(x, y));
    }

    /**
     *
     * @param where
     * @return
     */
    public boolean addCircle(Point where) {
        return add(CIRCLE, where);
    }

    /**
     *
     * @param x
     * @param y
     * @return
     */
    public boolean addCircle(int x, int y) {
        return add(CIRCLE, x, y);
    }

    /**
     *
     * @param where
     * @return
     */
    public boolean addCross(Point where) {
        return add(CROSS, where);
    }

    /**
     *
     * @param x
     * @param y
     * @return
     */
    public boolean addCross(int x, int y) {
        return add(CROSS, x, y);
    }

    /**
     *
     * @return
     */
    public boolean checkCircle() {
        for (Point p : circle) {
            if (checkRow(CIRCLE, p)) {
                return true;
            }
        }

        return false;
    }

    /**
     *
     * @return
     */
    public boolean checkCross() {
        for (Point p : cross) {
            if (checkRow(CROSS, p)) {
                return true;
            }
        }

        return false;
    }

    private boolean checkRow(int player, Point start) {
        int inARow;

        for (int i = 0; i < 8; i++) {
            inARow = 1;
            inARow += checkDirection(player, start, i);

            if (inARow > 4) {
                return true;
            }
        }

        return false;
    }

    private int checkDirection(int player, Point start, int direction) {
        Point checked = (Point) start.clone();

        switch (direction) {
        case 0 :
            checked.y--;

            break;

        case 1 :
            checked.y--;
            checked.x++;

            break;

        case 2 :
            checked.x++;

            break;

        case 3 :
            checked.x++;
            checked.y++;

            break;

        case 4 :
            checked.y++;

            break;

        case 5 :
            checked.y++;
            checked.x--;

            break;

        case 6 :
            checked.x--;

            break;

        case 7 :
            checked.x--;
            checked.y--;

            break;

        default :
            throw new IllegalArgumentException("direction");
        }

        switch (player) {
        case CROSS :
            if (cross.contains(checked)) {
                return 1 + checkDirection(player, checked, direction);
            } else {
                return 0;
            }
        case CIRCLE :
            if (circle.contains(checked)) {
                return 1 + checkDirection(player, checked, direction);
            } else {
                return 0;
            }
        default :
            throw new IllegalArgumentException("player");
        }
    }

    @Override
    public Object clone() {
        Object res = null;

        try {
            res = super.clone();
        } catch (CloneNotSupportedException ex) {

            // impossible
            Logger.getLogger(Desk.class.getName()).log(Level.SEVERE, null, ex);
        }

        return res;
    }
}


//~ Formatted by Jindent --- http://www.jindent.com
